//============================================================================
// NativeMethods.cs
//
// Copyright (c) 2005 U.S. TrailMaps, LLC
// THIS MATERIAL IS CONFIDENTIAL AND PROPRIETARY TO U.S. TRAILMAPS AND
// MAY NOT BE REPRODUCED, PUBLISHED OR DISCLOSED TO OTHERS WITHOUT COMPANY
// AUTHORIZATION.
//
// This work is derived from Waymex GPS Library for .Net version 2.7.9 source.
// Portions copyright (c) 2004-2005 Waymex IT Ltd
//============================================================================

using System;
using System.Runtime.InteropServices;

namespace Waymex.Gps.Garmin.Usb
{
	/// <summary>
	/// Methods to access unmanaged DLL functions.
	/// </summary>
	/// <remarks>
	/// For prototypes for many Win32 APIs, use .NET Reflector to examine the Microsoft.Win32.Win32Native class in mscorlib.
	/// In general, classes are preferred over structs because passing null pointers becomes easy and natural.
	/// To allow null to be passed to [out] pointer parameters, an override must be created.
	/// </remarks>
	internal sealed class NativeWin32Methods
	{
        private NativeWin32Methods()
		{
		}

		#region setupapi.h

		public const uint DIGCF_DEFAULT = 0x00000001;
		public const uint DIGCF_PRESENT = 0x00000002;
		public const uint DIGCF_ALLCLASSES = 0x00000004;
		public const uint DIGCF_PROFILE = 0x00000008;
		public const uint DIGCF_DEVICEINTERFACE = 0x00000010;

		[StructLayout(LayoutKind.Sequential)]
		public class SP_DEVICE_INTERFACE_DATA
		{
			public /*DWORD*/ uint cbSize = 0;
			public /*GUID*/ Guid InterfaceClassGuid = new Guid();
			public /*DWORD*/ uint Flags = 0;
			public /*ULONG_PTR*/ IntPtr Reserved = IntPtr.Zero;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
		public class SP_DEVICE_INTERFACE_DETAIL_DATA_EXACT
		{
			public /*DWORD*/ uint cbSize = 0;
			public /*TCHAR[ANYSIZE_ARRAY=1]*/ char DevicePath = '\0';
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public class SP_DEVICE_INTERFACE_DETAIL_DATA
		{
			public /*DWORD*/ uint cbSize = 0;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
			public /*TCHAR[ANYSIZE_ARRAY=1]*/ string DevicePath = "";
		}

		[StructLayout(LayoutKind.Sequential)]
		public class SP_DEVINFO_DATA
		{
			public /*DWORD*/ uint cbSize = 0;
			public /*GUID*/ Guid ClassGuid = new Guid();
			public /*DWORD*/ uint DevInst = 0;
			public /*ULONG_PTR*/ IntPtr Reserved = IntPtr.Zero;
		}

		[DllImport("setupapi.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool SetupDiDestroyDeviceInfoList(
			/*[in] HDEVINFO*/ IntPtr DeviceInfoSet
			);

		[DllImport("setupapi.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool SetupDiEnumDeviceInterfaces(
			/*[in] HDEVINFO*/ IntPtr DeviceInfoSet,
			/*[in] PSP_DEVINFO_DATA*/ [In] SP_DEVINFO_DATA DeviceInfoData,
			/*[in] const GUID**/ ref Guid InterfaceClassGuid,
			/*[in] DWORD*/ uint MemberIndex,
			/*[out] PSP_DEVICE_INTERFACE_DATA*/ [In,Out] SP_DEVICE_INTERFACE_DATA DeviceInterfaceData
			);

		[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern /*HDEVINFO*/ IntPtr SetupDiGetClassDevs(
			/*[in] const GUID**/ ref Guid ClassGuid,
			/*[in] PCTSTR*/ [In] string Enumerator,
			/*[in] HWND*/ IntPtr hwndParent,
			/*[in] DWORD*/ uint Flags
			);

		[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern /*BOOL*/ bool SetupDiGetDeviceInterfaceDetail(
			/*[in] HDEVINFO*/ IntPtr DeviceInfoSet,
			/*[in] PSP_DEVICE_INTERFACE_DATA*/ [In] SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
			/*[out] PSP_DEVICE_INTERFACE_DETAIL_DATA*/ [In,Out] SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
			/*[in] DWORD*/ uint DeviceInterfaceDetailDataSize,
			/*[out] PDWORD*/ out uint RequiredSize,
			/*[out] PSP_DEVINFO_DATA*/ [In,Out] SP_DEVINFO_DATA DeviceInfoData
			);

		#endregion

		#region winbase.h

		public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // ((HANDLE)(LONG_PTR)-1)

		public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
		public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
		public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
		public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000;
		public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
		public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
		public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
		public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000;
		public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
		public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
		public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;

		public const uint CREATE_NEW = 1;
		public const uint CREATE_ALWAYS = 2;
		public const uint OPEN_EXISTING = 3;
		public const uint OPEN_ALWAYS = 4;
		public const uint TRUNCATE_EXISTING = 5;

		[StructLayout(LayoutKind.Sequential)]
		public class OVERLAPPED
		{
			public /*ULONG_PTR*/ IntPtr Internal = IntPtr.Zero;
			public /*ULONG_PTR*/ IntPtr InternalHigh = IntPtr.Zero;
			public /*DWORD*/ uint Offset = 0;
			public /*DWORD*/ uint OffsetHigh = 0;
			public /*HANDLE*/ IntPtr hEvent = IntPtr.Zero;
		}

		[StructLayout(LayoutKind.Sequential)]
		public class SECURITY_ATTRIBUTES
		{
			public /*DWORD*/ uint nLength = 0;
			public /*LPVOID*/ IntPtr lpSecurityDescriptor = IntPtr.Zero;
			public /*BOOL*/ bool bInheritHandle = false;
		}

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool CancelIo(
			/*[in] HANDLE*/ IntPtr hFile
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool ClearCommError(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[out] LPDWORD*/ out uint lpErrors,
			/*[out] LPCOMSTAT*/ IntPtr lpStat
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool CloseHandle(
			/*[in] HANDLE*/ IntPtr hObject
			);

		[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern /*HANDLE*/ IntPtr CreateFile(
			/*[in] LPCTSTR*/ [In] string lpFileName,
			/*[in] DWORD*/ uint dwDesiredAccess,
			/*[in] DWORD*/ uint dwShareMode,
			/*[in] LPSECURITY_ATTRIBUTES*/ [In] SECURITY_ATTRIBUTES lpSecurityAttributes,
			/*[in] DWORD*/ uint dwCreationDisposition,
			/*[in] DWORD*/ uint dwFlagsAndAttributes,
			/*[in] HANDLE*/ IntPtr hTemplateFile
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool DeviceIoControl(
			/*[in] HANDLE*/ IntPtr hDevice,
			/*[in] DWORD*/ uint dwIoControlCode,
			/*[in] LPVOID*/ IntPtr lpInBuffer,
			/*[in] DWORD*/ uint nInBufferSize,
			/*[out] LPVOID*/ IntPtr lpOutBuffer,
			/*[in] DWORD*/ uint nOutBufferSize,
			/*[out] LPDWORD*/ out uint lpBytesReturned,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool GetCommModemStatus(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[out] LPDWORD*/ out uint lpModemStat
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool GetOverlappedResult(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped,
			/*[out] LPDWORD*/ out uint lpNumberOfBytesTransferred,
			/*[in] BOOL*/ bool bWait
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool ReadFile(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[out] LPVOID*/ IntPtr lpBuffer,
			/*[in] DWORD*/ uint nNumberOfBytesToRead,
			/*[out] LPDWORD*/ out uint lpNumberOfBytesRead,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool ReadFile(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[out] LPVOID*/ [Out] byte[] lpBuffer,
			/*[in] DWORD*/ uint nNumberOfBytesToRead,
			/*[out] LPDWORD*/ out uint lpNumberOfBytesRead,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool SetCommMask(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[in] DWORD*/ uint dwEvtMask
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool WaitCommEvent(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[out] LPDWORD*/ out uint lpEvtMask,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped
			);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern /*BOOL*/ bool WriteFile(
			/*[in] HANDLE*/ IntPtr hFile,
			/*[in] LPCVOID*/ [In] byte[] lpBuffer,
			/*[in] DWORD*/ uint nNumberOfBytesToWrite,
			/*[out] LPDWORD*/ out uint lpNumberOfBytesWritten,
			/*[in] LPOVERLAPPED*/ [In] OVERLAPPED lpOverlapped
			);

		#endregion

		#region winerror.h

		public const int ERROR_ACCESS_DENIED = 5;
		public const int ERROR_NO_MORE_ITEMS = 259;
		public const int ERROR_IO_PENDING = 997;

		#endregion

		#region winioctl.h

		public static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access)
		{
			return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method);
		}

		public const uint FILE_ANY_ACCESS = 0;
		public const uint FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
		public const uint FILE_READ_ACCESS = 0x0001;
		public const uint FILE_WRITE_ACCESS = 0x0002;

		public const uint METHOD_BUFFERED = 0;
		public const uint METHOD_IN_DIRECT = 1;
		public const uint METHOD_OUT_DIRECT = 2;
		public const uint METHOD_NEITHER = 3;

		public const uint FILE_DEVICE_UNKNOWN = 0x00000022;

		#endregion

		#region winnt.h

		public const uint GENERIC_READ = 0x80000000;
		public const uint GENERIC_WRITE = 0x40000000;
		public const uint GENERIC_EXECUTE = 0x20000000;
		public const uint GENERIC_ALL = 0x10000000;

		#endregion

		// TODO: The following have NOT been reviewed:

		[DllImport("kernel32.dll")]
		internal static extern Boolean SetCommState(IntPtr hFile, [In] ref DCB lpDCB);

		[DllImport("kernel32.dll")]
		internal static extern Boolean SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS lpCommTimeouts);

		[DllImport("kernel32.dll")]
		internal static extern Boolean SetupComm(IntPtr hFile, UInt32 dwInQueue, UInt32 dwOutQueue);

		[StructLayout( LayoutKind.Sequential )] internal struct COMMTIMEOUTS
		{
			//JH1.1: Changed Int32 to UInt32 to allow setting to MAXDWORD
			internal UInt32 ReadIntervalTimeout;
			internal UInt32 ReadTotalTimeoutMultiplier;
			internal UInt32 ReadTotalTimeoutConstant;
			internal UInt32 WriteTotalTimeoutMultiplier;
			internal UInt32 WriteTotalTimeoutConstant;
		}
		//JH1.1: Added to enable use of "return immediately" timeout.
		internal const UInt32 MAXDWORD = 0xffffffff;

		[StructLayout( LayoutKind.Sequential )] internal struct DCB
		{
			internal Int32 DCBlength;
			internal Int32 BaudRate;
			internal Int32 PackedValues;
			internal Int16 wReserved;
			internal Int16 XonLim;
			internal Int16 XoffLim;
			internal Byte  ByteSize;
			internal Byte  Parity;
			internal Byte  StopBits;
			internal Byte XonChar;
			internal Byte XoffChar;
			internal Byte ErrorChar;
			internal Byte EofChar;
			internal Byte EvtChar;
			internal Int16 wReserved1;
		}

		// Constants for dwEvtMask:
		internal const UInt32 EV_RXCHAR = 0x0001;
		internal const UInt32 EV_TXEMPTY = 0x0004;
		internal const UInt32 EV_CTS = 0x0008;
		internal const UInt32 EV_DSR = 0x0010;
		internal const UInt32 EV_RLSD = 0x0020;
		internal const UInt32 EV_BREAK = 0x0040;
		internal const UInt32 EV_ERR = 0x0080;
		internal const UInt32 EV_RING = 0x0100;

		// Constants for lpModemStat:
		internal const UInt32 MS_CTS_ON = 0x0010;
		internal const UInt32 MS_DSR_ON = 0x0020;
		internal const UInt32 MS_RING_ON = 0x0040;
		internal const UInt32 MS_RLSD_ON = 0x0080;

		//Constants for lpErrors:
		internal const UInt32 CE_RXOVER = 0x0001;
		internal const UInt32 CE_OVERRUN = 0x0002;
		internal const UInt32 CE_RXPARITY = 0x0004;
		internal const UInt32 CE_FRAME = 0x0008;
		internal const UInt32 CE_BREAK = 0x0010;
		internal const UInt32 CE_TXFULL = 0x0100;
		internal const UInt32 CE_IOE = 0x0400;

		[DllImport("kernel32.dll")]
		internal static extern Boolean GetCommProperties(IntPtr hFile, out COMMPROP cp);

		[StructLayout( LayoutKind.Sequential )] internal struct COMMPROP
		{
			internal UInt16 wPacketLength;
			internal UInt16 wPacketVersion;
			internal UInt32 dwServiceMask;
			internal UInt32 dwReserved1;
			internal UInt32 dwMaxTxQueue;
			internal UInt32 dwMaxRxQueue;
			internal UInt32 dwMaxBaud;
			internal UInt32 dwProvSubType;
			internal UInt32 dwProvCapabilities;
			internal UInt32 dwSettableParams;
			internal UInt32 dwSettableBaud;
			internal UInt16 wSettableData;
			internal UInt16 wSettableStopParity;
			internal UInt32 dwCurrentTxQueue;
			internal UInt32 dwCurrentRxQueue;
			internal UInt32 dwProvSpec1;
			internal UInt32 dwProvSpec2;
			internal Byte wcProvChar;
		}
	}
}
